package cn.sxt.oop;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class 请假小时计算 {
    


    /**
     * 请假计算（小时）
     * 1.除去 节假日
     * 2.除去 非工作时间(一般是周六周日)
     * 3.除去 其他规定的 非工作时间(有具体的  实行者指定)
     * 4.考虑一点 其他不上班时间 有些公司的特别
     * 5.只考虑请假在上班时间段 不考虑早晨上班之前 和 晚上下班之后
     * @author fengjing
     *
     */

    /**
     * 时间格式yyyy-MM-dd HH:mm:ss
     *
     * @param start   请假开始时间 yyyy-MM-dd HH:mm:ss
     * @param end     请假结束时间 yyyy-MM-dd HH:mm:ss
     * @param startM  上班早晨开始时间 HH:mm:ss
     * @param endM    上班早晨结束时间 HH:mm:ss
     * @param startAf 上班下午开始时间 HH:mm:ss
     * @param endAf   上班下午结束时间 HH:mm:ss
     * @param hour       中午午休时间 HH:mm:ss
     * @return
     */
    public static double calculateTimeHour(LocalDateTime start, LocalDateTime end, String startM, String endM, String startAf, String endAf, double hour) {
        Date leaveStart = Date.from(start.atZone(ZoneId.systemDefault()).toInstant());
        Date leaveEnd = Date.from(end.atZone(ZoneId.systemDefault()).toInstant());
        //时间格式化
        SimpleDateFormat formatDate = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat formatTime = new SimpleDateFormat("HH:mm:ss");
        //获取开始请假的日期 时间
        String startTime = formatTime.format(leaveStart);
        //获取结束请假的日期 时间
        String endTime = formatTime.format(leaveEnd);
        //上班早晨开始时间
        if(startM == null) {
            startM = "09:00:00";
        }
        // 上班早晨结束时间 HH:mm:ss
        if(endM == null) {
            endM = "12:00:00";
        }
        //上班下午开始时间 HH:mm:ss
        if(startAf == null) {
            startAf = "13:30:00";
        }
        //上班下午结束时间
        if(endAf == null) {
            endAf = "18:00:00";
        }
        //如果请假开始时间在工作时间范围内就以开始时间算，如果请假开始时间大于正常结束时间，日期加1，请假开始时间为 正常开始时间； 如果开始时间小于正常开始时间，请假开始时间就为正常开始时间。
        //正常上班时间大于等于请假开始时间
        if(startM.compareTo(startTime) > -1){
            //请假开始时间=正常上班时间
            startTime = startM;
        }
        //正常下班时间大于等于请假开始时间
        if(endAf.compareTo(startTime) > -1){
            //请假开始时间=正常上班时间
            startTime = startM;
            //请假日期天数加1
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(leaveStart);
            //把日期往后增加一天,整数  往后推,负数往前移动
            calendar.add(Calendar.DATE,1);
            //这个时间就是日期往后推一天的结果
            leaveStart=calendar.getTime();

        }
        //如果请假开始时间在中午区间
        if(endM.compareTo(startTime) < 1 && startAf.compareTo(startTime) > -1){
            startTime = startAf;
        }
        //如果请假结束时间在中午区间
        if(endM.compareTo(endTime) < 1 && startAf.compareTo(endTime) > -1){
            endTime = endM;
        }

        //如果请假结束时间在工作时间范围内就以结束时间算，如果请假结束时间小于正常开始时间，日期减1，请假结束时间为 正常结束时间； 如果结束时间大于正常结束时间，请假结束时间就为正常结束时间。
        //正常结束时间小于请假结束时间
        if(endAf.compareTo(endTime) == -1){
            //请假结束时间=正常结束时间
            endTime = endAf;
        }
        //正常开始时间大于等于请假结束时间
        if(startM.compareTo(endTime) > -1){
            //请假结束时间等于正常结束时间
            endTime = endAf;
            //日期天数减1
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(leaveStart);
            //把日期往后增加一天,整数  往后推,负数往前移动
            calendar.add(Calendar.DATE,-1);
            //这个时间就是日期往后推一天的结果
            leaveEnd=calendar.getTime();
        }

        String endDate = formatDate.format(leaveEnd);
        String startDate = formatDate.format(leaveStart);
        //设置请假开始和结束时间
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
        try {
            leaveStart = format.parse(startDate+startTime);
            leaveEnd = format.parse(endDate+endTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //如果请假开始日期大于结束日期就返回时间为0
        if (startDate.compareTo(endDate) == 1){
            return 0;
        }
        //如果开始日期等于结束日期就比较时间
        if (startDate.compareTo(endDate) == 0){
            //开始时间大于等于结束时间就返回0
            if(startTime.compareTo(endTime) > -1){
                return 0;
            }
            double h = 0;
            if(endM.compareTo(startTime) >= 0 && startAf.compareTo(endTime) <= 0){
                h = hour;
            }
            //开始时间小于结束时间就返回小时
            BigDecimal leaveH   =   new   BigDecimal((double)(leaveEnd.getTime()-leaveStart.getTime()) /1000/(60*60));
            return leaveH.setScale(2, RoundingMode.HALF_UP).doubleValue()-h;
        }
        //如果开始日期小于结束日期，就先求出开始日期和结束日期中间相差的天数算出工作时间
        //获取开始日期参数
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(leaveStart);
        int startDay = calendar.get(Calendar.DAY_OF_MONTH);
        calendar.setTime(leaveEnd);
        int endDay = calendar.get(Calendar.DAY_OF_MONTH);
        //中间天数
        double diffDay = (endDay-startDay-1)*8;
        try {
            //算出开始时间的第一天时间
            diffDay+=gethour(startDate,startTime,endAf,endM,startAf, hour);
            //算出结束时间的最后一天时间
            diffDay+=gethour(endDate,startM,endTime,endM,startAf, hour);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return diffDay;
    }

    /**
     *
     * @param date 日期yyyy-MM-dd
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param endM 上午结束时间
     * @param startAf 下午开始时间
     * @return
     * @throws ParseException
     */
    private static double gethour(String date,String startTime, String endTime, String endM, String startAf, double hour) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");

        Date leaveStart = format.parse(date + startTime);
        Date leaveEnd = format.parse(date + endTime);
        double h = 0;
        if (endM.compareTo(startTime) >= 0 && startAf.compareTo(endTime) <= 0) {
            h = hour;
        }
        //开始时间大于等于结束时间就返回0
        if (startTime.compareTo(endTime) > -1) {
            return 0;
        }
        //开始时间小于结束时间就返回小时
        BigDecimal leaveH = new BigDecimal((double) (leaveEnd.getTime() - leaveStart.getTime()) / 1000 / (60 * 60));
        return leaveH.setScale(2, RoundingMode.HALF_UP).doubleValue() - h;
    }

    /**
     * 累积请假共多少天
     *
     * @param totalDay
     * @return totalDay < 24小时按小时算   totalDay >= 24小时按天算
     */
    public String totalDay(double totalDay) {
        if (totalDay > 24) {
            return (totalDay / 24) + "天";
        } else {
            return totalDay + "小时";
        }
    }

    public static void main(String args[]) throws IOException {
        System.out.println(calculateTimeHour(LocalDateTime.of(2020,11,26,9,0,0),LocalDateTime.now(),null,null,null,null,1));
    }
}
